package testcase;

import static org.junit.Assert.*;

import controller.Scheduler;
import information.Line;
import information.Pier;

import org.junit.Before;
import org.junit.Test;


/**
 * @author Rigsby Chi (52584035), Michael Lau (52611921)
 * @version for Scheduler.java v3.0.2 refactor by Rigsby Chi(52584035)
 * @since 08-04-2013
 */

public class SchedulerTest {

	@Before
	// Base case: 2 pier with a line respectively
	// Pier 0: 1 line with startTime=0800, frequency=30, run=1, duration=15.
	// Pier 1: 1 line with startTime=0900, frequency=60, run=8, duration=30.
	public void setUp() {
		Scheduler.resetScheduler();
		// for checking time conflicts part only
		
	}

	
	@Test
	public void testGetSchedulerBySize() {
		int size[] = {1,2,3};
		Scheduler tempTimeS1 = Scheduler.getScheduler();
		Scheduler tempTimeS2 = Scheduler.getScheduler(size);
		assertEquals(tempTimeS1, tempTimeS2);
		Scheduler.resetScheduler();
	}
	
	@Test
	public void testGetSchedulerByPierArray(){
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(3);
		pier[0].addLine(new Line(800, 60, 1, 50, 1));
		Scheduler tempTimeS1 = Scheduler.getScheduler(pier, 1);
		Scheduler tempTimeS2 = Scheduler.getScheduler(pier, 1);
		assertEquals(tempTimeS1,tempTimeS2);
		Scheduler.resetScheduler();
	}
	
	@Test
	public void testGetSchedulerByEmpty(){
		Scheduler tempTimeS1 = Scheduler.getScheduler();
		Scheduler tempTimeS2 = Scheduler.getScheduler();
		assertEquals(tempTimeS1,tempTimeS2);
		Scheduler.resetScheduler();
	}
	
	
	// TESTS for timeConflicts(Line, int)
	@Test
	// Test case 1: startTime = 8:40, frequency = 30, runs = 1, duration = 15.
	public void testTimeConflicts_840_30_1_15() {
		Pier testPier[] = new Pier[2];

		testPier[0] = new Pier(1);
		testPier[1] = new Pier(1);
		testPier[0].addLine(new Line(800, 30, 1, 15, 1));
		testPier[1].addLine(new Line(900, 60, 8, 30, 1));
		Scheduler scheduler = Scheduler.getScheduler(testPier, 2);
		boolean result;
		result = scheduler.timeConflicts(new Line(840, 30, 1, 15, 1), 1);
		assertFalse(result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 2: startTime = 10:00, frequency = 30, runs = 1, duration = 15.
	public void testTimeConflicts_1000_30_1_15() {
		Pier testPier[] = new Pier[2];

		testPier[0] = new Pier(1);
		testPier[1] = new Pier(1);
		testPier[0].addLine(new Line(800, 30, 1, 15, 1));
		testPier[1].addLine(new Line(900, 60, 8, 30, 1));
		Scheduler scheduler = Scheduler.getScheduler(testPier, 2);
		boolean result;
		result = scheduler.timeConflicts(new Line(1000, 30, 1, 15, 1), 1);
		assertTrue(result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 3: startTime = 16:00, frequency = 30, runs = 1, duration = 15.
	public void testTimeConflicts_1600_30_1_15() {
		Pier testPier[] = new Pier[2];

		testPier[0] = new Pier(1);
		testPier[1] = new Pier(1);
		testPier[0].addLine(new Line(800, 30, 1, 15, 1));
		testPier[1].addLine(new Line(900, 60, 8, 30, 1));
		Scheduler scheduler = Scheduler.getScheduler(testPier, 2);
		boolean result;
		result = scheduler.timeConflicts(new Line(1600, 30, 1, 15, 1), 1);
		assertTrue(result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 4: startTime = 17:00, frequency = 30, runs = 1, duration = 15.
	public void testTimeConflicts_1700_30_1_15() {
		Pier testPier[] = new Pier[2];

		testPier[0] = new Pier(1);
		testPier[1] = new Pier(1);
		testPier[0].addLine(new Line(800, 30, 1, 15, 1));
		testPier[1].addLine(new Line(900, 60, 8, 30, 1));
		Scheduler scheduler = Scheduler.getScheduler(testPier, 2);
		boolean result;
		result = scheduler.timeConflicts(new Line(1700, 30, 1, 15, 1), 1);
		assertFalse(result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 5: startTime = 8:40, frequency = 30, runs = 2, duration = 15.
	public void testTimeConflicts_840_30_2_15() {
		Pier testPier[] = new Pier[2];

		testPier[0] = new Pier(1);
		testPier[1] = new Pier(1);
		testPier[0].addLine(new Line(800, 30, 1, 15, 1));
		testPier[1].addLine(new Line(900, 60, 8, 30, 1));
		Scheduler scheduler = Scheduler.getScheduler(testPier, 2);
		boolean result;
		result = scheduler.timeConflicts(new Line(840, 30, 2, 15, 1), 1);
		assertTrue(result);
		Scheduler.resetScheduler();
	}

	// TESTS for pierPrioritySort()
	@Test
	public void testPrioritySort_120() {
		class PierStub extends Pier {
			private int priority;

			PierStub(int priority) {
				super(1); // set size to be 1
				this.priority = priority;
			}

			@Override
			public double getPriority() {
				return priority;
			}
		}
		Pier[] pier = new PierStub[3];
		pier[0] = new PierStub(3);
		pier[1] = new PierStub(1);
		pier[2] = new PierStub(2);
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 3);
		int result[] = { 1, 2, 0 };
		assertArrayEquals(tempTimeS.pierPrioritySort(), result);
		Scheduler.resetScheduler();
	}

	@Test
	public void testPrioritySort_210() {
		class PierStub extends Pier {
			private double priority;

			PierStub(double priority) {
				super(1); // set size to be 1
				this.priority = priority;
			}

			@Override
			public double getPriority() {
				return priority;
			}
		}
		Pier[] pier = new PierStub[3];
		pier[0] = new PierStub(2);
		pier[1] = new PierStub(1);
		pier[2] = new PierStub(0);
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 3);
		int result[] = { 2, 1, 0 };
		assertArrayEquals(tempTimeS.pierPrioritySort(), result);
		Scheduler.resetScheduler();
	}

	@Test
	public void testPrioritySort_012() {
		class PierStub extends Pier {
			private double priority;

			PierStub(double priority) {
				super(1); // set size to be 1
				this.priority = priority;
			}

			@Override
			public double getPriority() {
				return priority;
			}
		}
		Pier[] pier = new PierStub[3];
		pier[0] = new PierStub(1);
		pier[1] = new PierStub(2);
		pier[2] = new PierStub(3);
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 3);
		int result[] = { 0, 1, 2 };
		assertArrayEquals(tempTimeS.pierPrioritySort(), result);
		Scheduler.resetScheduler();
	}

	@Test
	public void testPrioritySort_201() {
		class PierStub extends Pier {
			private double priority;

			PierStub(double priority) {
				super(1); // set size to be 1
				this.priority = priority;
			}

			@Override
			public double getPriority() {
				return priority;
			}
		}
		Pier[] pier = new PierStub[3];
		pier[0] = new PierStub(1);
		pier[1] = new PierStub(1);
		pier[2] = new PierStub(0);
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 3);
		int result[] = { 2, 0, 1 };
		assertArrayEquals(tempTimeS.pierPrioritySort(), result);
		Scheduler.resetScheduler();
	}

	
	// TESTS for modifyLine(int, int, Line)
	@Test
	// Test case 1: Reduce the runs by 1 and it will not be moved (No size
	// problem)
	public void testModifyLine_pier_unchange() {
		Pier[] pier = new Pier[3];
		pier[0] = new Pier(1);
		pier[1] = new Pier(1);
		pier[2] = new Pier(1);
		pier[0].addLine(new Line(800, 60, 3, 30, 1));
		pier[1].addLine(new Line(800, 60, 3, 30, 1));
		pier[2].addLine(new Line(800, 60, 3, 30, 1));
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 3);
		// reduce runs by 1
		int result = tempTimeS.modifyLine(0, 0, new Line(800, 60, 2, 30, 1));
		assertEquals(0, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 2: Line will be moved to another Pier since the original pier
	// is busy (No size problem)
	public void testModifyLine_pier_change() {
		Pier[] pier = new Pier[3];
		pier[0] = new Pier(1);
		pier[1] = new Pier(1);
		pier[2] = new Pier(1);
		pier[0].addLine(new Line(800, 60, 3, 30, 1));
		pier[0].addLine(new Line(1300, 60, 3, 30, 1));
		pier[1].addLine(new Line(800, 60, 3, 30, 1));
		pier[2].addLine(new Line(800, 60, 3, 30, 1));
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 3);
		// reduce runs by 1
		int result = tempTimeS.modifyLine(0, 0, new Line(1300, 60, 3, 30, 1));
		assertEquals(1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 3: Line will be moved to another Pier since the size problem
	public void testModifyLine_pierSize_change_1() {
		Pier[] pier = new Pier[3];
		pier[0] = new Pier(3);
		pier[1] = new Pier(1);
		pier[2] = new Pier(2);
		pier[0].addLine(new Line(800, 60, 4, 50, 1));
		pier[1].addLine(new Line(1500, 60, 5, 30, 1));
		pier[2].addLine(new Line(800, 60, 5, 50, 1));
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 3);
		// reduce runs by 1
		int result = tempTimeS.modifyLine(1, 0, new Line(1500, 60, 3, 30, 2));
		assertEquals(2, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 3: Line will be moved to another Pier since the size problem
	public void testModifyLine_pierSize_change_2() {
		Pier[] pier = new Pier[3];
		pier[0] = new Pier(1);
		pier[1] = new Pier(2);
		pier[2] = new Pier(3);
		pier[0].addLine(new Line(800, 60, 4, 50, 1));
		pier[1].addLine(new Line(1500, 60, 3, 50, 1));
		pier[2].addLine(new Line(800, 60, 4, 50, 1));
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 3);
		// reduce runs by 1
		int result = tempTimeS.modifyLine(1, 0, new Line(1500, 60, 3, 30, 3));
		assertEquals(2, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 4: No possible target pier since time conflict
	public void testModifyLine_conflict_time() {
		Pier[] pier = new Pier[3];
		pier[0] = new Pier(1);
		pier[1] = new Pier(1);
		pier[2] = new Pier(1);
		pier[0].addLine(new Line(800, 60, 3, 50, 1));
		pier[0].addLine(new Line(1300, 60, 3, 50, 1));
		pier[1].addLine(new Line(800, 60, 3, 30, 1));
		pier[2].addLine(new Line(800, 60, 3, 50, 1));
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 3);
		// reduce runs by 1
		int result = tempTimeS.modifyLine(0, 1, new Line(800, 60, 3, 30, 1));
		assertEquals(-1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 5: No possible target pier since time conflict
	public void testModifyLine_conflict_shipSize() {
		Pier[] pier = new Pier[3];
		pier[0] = new Pier(1);
		pier[1] = new Pier(1);
		pier[2] = new Pier(1);
		pier[0].addLine(new Line(800, 60, 3, 50, 1));
		pier[0].addLine(new Line(1300, 60, 3, 50, 1));
		pier[1].addLine(new Line(800, 60, 3, 30, 1));
		pier[2].addLine(new Line(800, 60, 3, 50, 1));
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 3);
		// reduce runs by 1
		int result = tempTimeS.modifyLine(0, 1, new Line(1300, 60, 3, 30, 2));
		assertEquals(-1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 6: Detail unchanged
	public void testModifyLine_noChange() {
		Pier[] pier = new Pier[3];
		pier[0] = new Pier(1);
		pier[0].addLine(new Line(800, 60, 3, 50, 1));
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 1);
		int result = tempTimeS.modifyLine(0, 0, new Line(800, -1, -1, -1, -1));
		assertEquals(-2, result);
		Scheduler.resetScheduler();
	}

	
	// TESTS for deleteLine(int,int)
	@Test
	// Test case 1: check whether a line can be deleted successfully
	public void testDeleteLine_normal() {
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(3);
		pier[0].addLine(new Line(800, 60, 1, 50, 1));
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 1);
		boolean result = tempTimeS.deleteLine(0, 0);
		assertTrue(result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 2: check whether delete the first line will change the second
	// line to become the first one
	public void testDeleteLine_further() {
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(3);
		pier[0].addLine(new Line(800, 60, 1, 50, 1));
		pier[0].addLine(new Line(900, 60, 1, 50, 1));
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 1);
		tempTimeS.deleteLine(0, 0);
		int result[] = tempTimeS.getLine(0, 0);
		int expected[] = { 900, 60, 1, 50, 1 };
		assertArrayEquals(expected, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 3: check whether a line can be deleted if it isn't exist
	public void testDeleteLine_noLine() {
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(3);
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 1);
		boolean result = tempTimeS.deleteLine(0, 0);
		assertFalse(result);
		Scheduler.resetScheduler();
	}

	// TESTS for timeRegister(Line)
	@Test
	// Test case 1: No pier with suitable size for the line
	public void testTimeRegister_size_noPier() {
		int result;
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(1);
		Scheduler tsForRegister = Scheduler.getScheduler(pier, 1);
		result = tsForRegister.timeRegister(new Line(800, 60, 6, 15, 2));
		assertEquals(-1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 2: Pier 0 has suitable size for the line
	public void testTimeRegister_size_firstPier() {
		int result;
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(2);
		Scheduler tsForRegister = Scheduler.getScheduler(pier, 1);
		result = tsForRegister.timeRegister(new Line(800, 60, 6, 15, 2));
		assertEquals(0, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 3: The second Pier (pier 1) has suitable size for the line
	public void testTimeRegister_size_secondPier() {
		int result;
		Pier pier[] = new Pier[3];
		pier[0] = new Pier(1);
		pier[1] = new Pier(2);
		pier[2] = new Pier(3);
		Scheduler tsForRegister = Scheduler.getScheduler(pier, 3);
		result = tsForRegister.timeRegister(new Line(800, 60, 6, 15, 2));
		assertEquals(1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 4: Both pier 0 and pier 1 has suitable size for the line, but
	// pier 1's size is closer to the line
	public void testTimeRegister_size_bothPiers() {
		int result;
		Pier pier[] = new Pier[3];
		pier[0] = new Pier(3);
		pier[1] = new Pier(2);
		pier[2] = new Pier(1);
		Scheduler tsForRegister = Scheduler.getScheduler(pier, 3);
		result = tsForRegister.timeRegister(new Line(800, 60, 6, 15, 2));
		assertEquals(1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 5: Invalid data, more than a day
	public void testTimeRegister_endTime_large() {
		int result;
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(1);
		Scheduler tsForRegister = Scheduler.getScheduler(pier, 1);
		result = tsForRegister.timeRegister(new Line(800, 60, 20, 30, 2));
		assertEquals(-1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 6: Invalid data, 25:00
	public void testTimeRegister_startTime_large() {
		int result;
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(1);
		Scheduler tsForRegister = Scheduler.getScheduler(pier, 1);
		result = tsForRegister.timeRegister(new Line(2500, 60, 5, 30, 2));
		assertEquals(-1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 7: Invalid data, -100 startTime
	public void testTimeRegister_starttime_small() {
		int result;
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(1);
		Scheduler tsForRegister = Scheduler.getScheduler(pier, 1);
		result = tsForRegister.timeRegister(new Line(-100, 60, 1, 30, 2));
		assertEquals(-1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 8: Invalid data, 8:99 StartTime
	public void testTimeRegister_startTime_invalid() {
		int result;
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(1);
		Scheduler tsForRegister = Scheduler.getScheduler(pier, 1);
		result = tsForRegister.timeRegister(new Line(899, 60, 1, 30, 2));
		assertEquals(-1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 9: Invalid data, freq is shorter than duration
	public void testTimeRegister_freq_short() {
		int result;
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(1);
		Scheduler tsForRegister = Scheduler.getScheduler(pier, 1);
		result = tsForRegister.timeRegister(new Line(800, 30, 5, 60, 2));
		assertEquals(-1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 10: Invalid data, 0 run
	public void testTimeRegister_runs_invalid() {
		int result;
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(1);
		Scheduler tsForRegister = Scheduler.getScheduler(pier, 1);
		result = tsForRegister.timeRegister(new Line(800, 60, 0, 30, 1));
		assertEquals(-1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 10: Invalid data, 0 run
	public void testTimeRegister_duration_invalid() {
		int result;
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(1);
		Scheduler tsForRegister = Scheduler.getScheduler(pier, 1);
		result = tsForRegister.timeRegister(new Line(800, 60, 2, 0, 1));
		assertEquals(-1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 11: have a time conflict
	public void testTimeRegister_timeConflict() {
		int result;
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(1);
		pier[0].addLine(new Line(800, 60, 2, 30, 1));
		Scheduler tsForRegister = Scheduler.getScheduler(pier, 1);
		result = tsForRegister.timeRegister(new Line(800, 60, 1, 15, 1));
		assertEquals(-1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 12: valid time setting but invalid ship size
	public void testTimeRegister_shipSize_invalid() {
		int result;
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(1);
		Scheduler tsForRegister = Scheduler.getScheduler(pier, 1);
		result = tsForRegister.timeRegister(new Line(800, 60, 2, 30, 2));
		assertEquals(-1, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case 13: no checking
	public void testTimeRegister_noChecking() {
		boolean result;
		Pier pier[] = new Pier[2];
		pier[0] = new Pier(1);
		pier[1] = new Pier(1);
		Scheduler tsForRegister = Scheduler.getScheduler(pier, 2);
		result = tsForRegister.timeRegister(new Line(800, 60, 0, 30, 2), 1);
		assertTrue(result);
		Scheduler.resetScheduler();
	}
	
	@Test
	// Test case 13: adding the first line
	public void testTimeRegister_firstLine() {
		int result;
		int pierSize[] = new int[3];
		pierSize[0] = 2;
		pierSize[1] = 1;
		pierSize[2] = 3;
		Scheduler tsForRegister = Scheduler.getScheduler(pierSize);
		result = tsForRegister.timeRegister(new Line(800, 60, 1, 30, 1));
		assertEquals(1, result);
		Scheduler.resetScheduler();
	}

	
	// TESTS for getter functions
	@Test
	// Test case for getNumberOfLines(int)
	public void testGetNumberOfLine() {
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(1);
		pier[0].addLine(new Line(800, 60, 1, 50, 1));
		pier[0].addLine(new Line(900, 60, 1, 50, 1));
		pier[0].addLine(new Line(1000, 60, 1, 50, 1));
		pier[0].addLine(new Line(1100, 60, 1, 50, 1));
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 1);
		int result = tempTimeS.getNumberOfLines(0);
		assertEquals(4, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case for getSizeOfPier(int)
	public void testGetSizeOfPier() {
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(3);
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 1);
		int result = tempTimeS.getSizeOfPier(0);
		assertEquals(3, result);
		Scheduler.resetScheduler();
	}

	@Test
	// Test case for getLine(int, int)
	public void testGetLine() {
		Pier pier[] = new Pier[1];
		pier[0] = new Pier(3);
		pier[0].addLine(new Line(800, 60, 1, 50, 1));
		Scheduler tempTimeS = Scheduler.getScheduler(pier, 1);
		int result[] = tempTimeS.getLine(0, 0);
		int expected[] = { 800, 60, 1, 50, 1 };
		assertArrayEquals(expected, result);
		Scheduler.resetScheduler();
	}
}
